package demo.codeanalyzer.processor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
import com.sun.tools.javac.model.JavacElements;

import demo.codeanalyzer.main.Resource;

/**
 * Visitor class which visits different nodes of the input source file, extracts
 * the required atribute of the visiting class, its mehods, fields, annotations
 * etc and set it in the java class model.
 * 
 * @author Seema Richard (Seema.Richard@ust-global.com)
 * @author Deepa Sobhana (Deepa.Sobhana@ust-global.com)
 */
public class PrintingVisitor extends TreePathScanner<Object, Trees> {

	private CodeGenerator codeGenerator;

	private PrintingVisitor(CodeGenerator generator) {
		this.codeGenerator = generator;
	}

	public static PrintingVisitor create(CodeGenerator generator) {
		PrintingVisitor instance = new PrintingVisitor(generator);
		if (null == generator) {
			generator = CodeGeneratorFactory.rdfCodeGenerator();
		}
		generator.setVisitor(instance);
		return instance;
	}

	private boolean isParsingNamespaceClass;

	private CodeGenerator oldCodeGenerator;

	@Override
	public Object visitClass(ClassTree classTree, Trees trees) {
		String modifier = classTree.getModifiers().toString();
		Pattern enumPattern = Pattern
				.compile(".*\\s*\\w+\\s+enum\\s+\\w+\\s*[{](.|\\s)*");
		if (isEnum(classTree, enumPattern))
			return codeGenerator.printEnum(classTree, trees);

		if (isParsingNamespaceClass(classTree)) {
			oldCodeGenerator = codeGenerator;
			codeGenerator = CodeGeneratorFactory.nameSpaceCodeGenerator(this);
		}
		Object result = codeGenerator.printClass(classTree, trees);
		this.resetCodeGenerator();
		return result;
	}

	private void resetCodeGenerator() {
		if (null != oldCodeGenerator) {
			this.codeGenerator = oldCodeGenerator;
		}
	}

	private boolean isParsingNamespaceClass(ClassTree classTree) {
		return "Namespaces".equals(classTree.getSimpleName().toString());
	}

	private boolean isEnum(ClassTree classTree, Pattern enumPattern) {
		return enumPattern.matcher(classTree.toString()).matches();
	}

	public void begin() {
	}

	@Override
	public Object visitMethod(MethodTree methodTree, Trees trees) {
		codeGenerator.printMethod(methodTree);
		return null;
	}

	@Override
	public Object visitVariable(VariableTree variableTree, Trees trees) {
		if (isParsingNamespaceClass)
			return codeGenerator.processNamespaces(variableTree, trees);
		Object result = codeGenerator.printVariable(variableTree, trees);
		return result;
	}

	public Object visitParentClass(ClassTree classTree, Trees trees) {
		return super.visitClass(classTree, trees);
	}

	public Object visitParentVariable(VariableTree variableTree, Trees trees) {
		return super.visitVariable(variableTree, trees);
	}

}
